﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace AircraftBattleServer
{
    public class BackgroundEngine
    {
        public void Run()
        {
            // Background engine main loop
            while (true)
            {
                UpdateMapData();
                Thread.Sleep(Constants.MapDataUpdateInterval);
            }
        }

        // Update the map data
        public void UpdateMapData()
        {
            lock (GameEngineService.mapdata)
            {
                List<Missile> missiles = GameEngineService.mapdata.missiles;
                List<Missile> missilelistToDelete = new List<Missile>();
                List<Aircraft> aclistToDelete = new List<Aircraft>();
                Dictionary<int, Aircraft> aircrafts = GameEngineService.mapdata.aircrafts;

                if (!GameEngineService.gameStarted) return;

                // Check if the game shall end
                if (CheckGameEnd(GameEngineService.mapdata)) return;

                // Check died aircrafts
                foreach (Aircraft ac in aircrafts.Values)
                {
                    if (ac.Die()) aclistToDelete.Add(ac);
                }

                // Delete died aircrafts
                foreach (Aircraft ac in aclistToDelete)
                {
                    aircrafts.Remove(ac.id);
                }

                // Update missile positions and check hits
                foreach (Missile m in missiles)
                {
                    m.Move();
                    if (m.position.x > Constants.CanvasWidth + Constants.MissileOutOfCanvasBuffer
                        || m.position.x < 0 - Constants.MissileOutOfCanvasBuffer
                        || m.position.y > Constants.CanvasHeight + Constants.MissileOutOfCanvasBuffer
                        || m.position.y < 0 - Constants.MissileOutOfCanvasBuffer)
                    {
                        missilelistToDelete.Add(m);
                    }
                    else 
                    {
                        this.CheckAnyAircraftHit(m);
                    }
                }

                // Delete missiles which flied out of the canvas
                foreach (Missile m in missilelistToDelete)
                {
                    missiles.Remove(m);
                }
            }
        }

        private bool CheckGameEnd(MapData mapData)
        {
            int cnt1 = 0, cnt2 = 0;
            foreach (User u in mapData.userList)
            {
                Console.WriteLine("u.craftId: {0}", u.craftID);
                if (mapData.aircrafts.Keys.Contains(u.craftID))
                {
                    if (u.team == 1) cnt1++;
                    else cnt2++;
                }
            }

            foreach (int ac in mapData.aircrafts.Keys)
            {
                Console.WriteLine("aircraft id: {0}", ac);
            }

            if (cnt1 == 0 && cnt2 == 0)
            {
                // it's a draw
                mapData.winer = 3;
            }
            else if (cnt1 == 0)
            {
                // team 2 wins
                mapData.winer = 2;
            }
            else if (cnt2 == 0)
            {
                // team 1 wins
                mapData.winer = 1;
            }

            if (mapData.winer > 0)
            {
                GameEngineService.gameStarted = false;
                Thread.Sleep(1000); // wait for all the clients get the game end info
                mapData.Clear();
                Console.WriteLine("winer: team {0}...", mapData.winer);
                return true;
            }
            else
            {
                return false;
            }
        }

        private void CheckAnyAircraftHit(Missile m)
        {
            foreach (Aircraft ac in GameEngineService.mapdata.aircrafts.Values)
            {
                if (ac.alive && this.Hit(m, ac))
                {
                    // set alive to false
                    ac.alive = false;
                    // remove missile by set a position out of the canvas. Then,
                    // it will be deleted properly in the next loop
                    m.position.x = -100;
                    Console.WriteLine("Aircarft {0} is hit...", ac.id);
                }
            }
        }

        private bool Hit(Missile m, Aircraft ac)
        {
            return (ServerUtility.Distance(m.position, ac.Center) < HitRadius) ? true : false;
        }

        public double HitRadius {
            get 
            { 
                double radius = Math.Min(Constants.AircraftImageWidth, Constants.AircraftImageHeight)/2;
                return radius - Constants.HitSweetBuffer;
            }
        }
    }
}
